<?php
class Api_Category extends Api
{

    protected static $cacheCategory = array();

    /**
     * @param <type> $id id_category
     * @return <type> Category
     */
    public function getCategoryById($id)
    {
        if(is_numeric($id))
            return CategoryTable::getCategoryById ($id);
        return false;
    }

    /**
     * @param <type> $cat_name
     * @return <type> Category
     */
    public function getCategoryByName($cat_name)
    {
        return CategoryTable::getCategoryByName($cat_name);
    }

    /**
     * Get First Root Category
     * @return <type> Category Object
     */
    public function getRoot()
    {
        return CategoryTable::getInstance()->getTree()->fetchRoot();
    }

    /**
     * Get All Root Nodes
     * @return <type> Array Category
     */
    public function getRoots()
    {
        return CategoryTable::getInstance()->getTree()->fetchRoots();
    }

    /**
     * Get Cache Array Category
     * @return <type> Array
     */
    public function getAllCategory()
    {
        if(isset(self::$cacheCategory['root']))
            $tree = self::$cacheCategory['root'];
        else{
            $tree = CategoryTable::getInstance()->getTree()->fetchTree();
            self::$cacheCategory['root'] = $tree;
        }

        if($tree)
            return $tree->toArray();
        
        return $tree;
    }


    /**
     * Get Tree Category
     * @example
     *          Array(
     *                  0 => Array(
     *                          'id' => 1
     *                          'children' => Array()
     *                      ),
     *                  1 => Array(
     *                          'id' => 2
     *                      )
     *              )
     * @param <type> $include_root
     * @return <type> Array
     */
    public function getTree($include_root = true)
    {
        $tree = $this->getAllCategory();

        if(!$include_root)
            array_shift ($tree);
        
        return $this->parseTree($tree);
    }

    /**
     * parse List Tree
     * @param <type> $list
     * @return <type> Array
     */
    private function parseTree(&$list)
    {
        $result = array();

        while(count($list) > 1)
        {
            $node = array_shift($list);
            
            if($list[0]['level'] > $node['level']){
                $node['children'] = $this->parseTree($list);
            }
            elseif($list[0]['level'] < $node['level']){
                return array_merge ($result,array($node));
            }

            $result[] = $node;

            if(count($list) == 1)
            {
                if($list[0]['level'] == $node['level'])
                    $result[] = $list[0];
                elseif($list[0]['level'] > $node['level'])
                    $node['children'] = $list;
                else
                    return $list;
            }
        }

        return $result;
    }

    /**
     * Return List Child Category Has Structured
     * @param <type> $list list category has structered
     * @param <type> $id
     * @return <type> Array
     */
    private function getChildren($list,$id)
    {
        $result = array();
        
        foreach($list as $row){
            
            if($row['id'] == $id){
                return $row['children'];
            }

            if(isset($row['children'])){
                //call recursion
                $result = array_merge($result,$this->getChildren($row['children'],$id));
            }
        }
        return $result;
    }

    /**
     * Create, Edit, Update, Delete Category Function
     * I don't how to write these method ???
     * Which data will be inputed and ouputed ?
     * Waiting for a big idea :)
     */
    public function createNewRoot($root_name)
    {
        $root = new Category();
        $root->name = $root_name;
        $root->save();
        
        $tree = self::getInstance()->getTree();
        return $tree->createRoot($root);
    }

    public function createCategory($data)
    {
        
    }

    public function updateCategory($data)
    {
        if(isset($data['id']) && is_numeric($data['id'])){
            //update category
        }

        return null;
    }
    
    
    //list of category methods
    /**
     * hasPrevSibling
     * hasNextSibling
     * hasChildren
     * hasParent
     * getPrevSibling
     * getNextSibling
     * getSiblings
     * getFirstChild
     * getLastChild
     * getChildren
     * getDescendants
     * getParent
     * getAncestors
     * getPath
     * getNumberChildren
     * getNumberDescendants
     * insertAsParentOf
     * insertAsPrevSiblingOf
     * insertAsNextSiblingOf
     * insertAsFirstChildOf
     * insertAsLastChildOf
     * moveAsPrevSiblingOf
     * moveAsNextSiblingOf
     * moveAsFirstChildOf
     * moveAsLastChildOf
     * makeRoot
     * addChild
     * isLeaf
     * isRoot
     * isDescendantOf
     * isValidNode
     * getLevel
     * getRootValue
     */
    
    /**
     * Move A Category To Another Category
     * $catId : id category was moved
     * $targetId : id target category which was moved to
     * $position : sibling ( before, after ) | inside (as last child)
     * 
     * @return return false if not success
     */
    public function moveCategory($catId,$targetId,$position)
    {
        $cat = CategoryTable::getCategoryById($catId);
        if(!$cat)
            return false;
        
        $target = CategoryTable::getCategoryById($targetId);
        if(!$target)
            return false;
        
        switch ($position)
        {
            case 'before':
                $cat->moveAsPrevSiblingOf($target);
                break;
            case 'after':
                $cat->moveAsNextSiblingOf($target);
                break;
            case 'inside':
                $cat->moveAsLastChildOf($target);
                break;
        }
    }
    
}
